/**
 * @file lv_lang.c
 *
 */

/*********************
 *      INCLUDES
 *********************/
#include "lv_lang.h"
#if LV_USE_MULTI_LANG

#include "../lvgl/src/lv_misc/lv_gc.h"

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void lang_set_core(lv_obj_t * obj);

/**********************
 *  STATIC VARIABLES
 **********************/
static uint8_t lang_act = 0;
static const void * (*get_txt)(uint16_t);

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

/**
 * Change the language
 * @param lang_id the id of the
 */
void lv_lang_set(uint8_t lang_id)
{
    lang_act = lang_id;

    lv_disp_t * d;
    _LV_LL_READ(LV_GC_ROOT(_lv_disp_ll), d) {
        lv_obj_t * s;
        _LV_LL_READ(d->scr_ll, s) {
            lv_signal_send(s, LV_SIGNAL_LANG_CHG, NULL);
            lang_set_core(s);
        }
    }

    lang_set_core(lv_disp_get_scr_act(NULL));
#if USE_LV_WATCH_LANG_ARABIC != 0
        lv_obj_t * act = lv_scr_act();
        lv_obj_t * obj;
        _LV_LL_READ(act->child_ll, obj) {
            if(lang_act == LANG_AR) {
                lv_obj_set_base_dir(obj, LV_BIDI_DIR_RTL);
            } else {
                lv_obj_set_base_dir(obj, LV_BIDI_DIR_LTR);
            }
        }
#endif
}

/**
 * Set a function to get the texts of the set languages from a `txt_id`
 * @param fp a function pointer to get the texts
 */
void lv_lang_set_text_func(const void * (*fp)(uint16_t))
{
    get_txt = fp;
}

/**
 * Use the function set by `lv_lang_set_text_func` to get the `txt_id` text in the set language
 * @param txt_id an ID of the text to get
 * @return the `txt_id` txt on the set language
 */
const void * lv_lang_get_text(uint16_t txt_id)
{
    if(get_txt == NULL) {
        LV_LOG_WARN("lv_lang_get_text: text_func is not specified");
        return NULL;                    /*No text_get function specified */
    }
    if(txt_id == LV_LANG_TXT_ID_NONE) {
        LV_LOG_WARN("lv_lang_get_text: attempts to get invalid text ID");
        return NULL;      /*Invalid txt_id*/
    }

    return get_txt(txt_id);
}


/**
 * Return with ID of the currently selected language
 * @return pointer to the active screen object (loaded by 'lv_scr_load()')
 */
uint8_t lv_lang_act(void)
{
    return lang_act;
}


/**********************
 *   STATIC FUNCTIONS
 **********************/

/**
 * Change the language of the children. (Called recursively)
 * @param obj pointer to an object
 */
static void lang_set_core(lv_obj_t * obj)
{
    lv_obj_t * i;
    _LV_LL_READ(obj->child_ll, i) {
        lv_signal_send(i, LV_SIGNAL_LANG_CHG, NULL);

        lang_set_core(i);
    }
}

lv_res_t lv_lang_label_sign_cb(struct _lv_obj_t * obj, lv_signal_t sign, void * param)
{
    lv_label_ext_t * ext = (lv_label_ext_t *)lv_obj_get_ext_attr(obj);
    if(ext->old_sign_cb) ext->old_sign_cb(obj, sign, param);

    uint32_t textid = obj->user_data.user_num;
    if(LV_SIGNAL_LANG_CHG == sign) {
        if(textid != LV_LANG_TXT_ID_NONE) {
            const char * lang_txt = lv_lang_get_text(textid);
            if(lang_txt) {
                lv_label_set_text(obj, lang_txt);
            } else {
                LV_LOG_WARN("lv_lang_get_text return NULL for a label's text");
            }
        }
    }
    return LV_RES_OK;
}

/**
 *Set a text ID which refers a the same text but in a different languages
 * @param label pointer to a label object
 * @param txt_id ID of the text
 */
void lv_label_set_text_id(lv_obj_t * label, uint32_t txt_id)
{
    label->user_data.user_num = txt_id;                       //save text id

    if(lv_lang_label_sign_cb != lv_obj_get_signal_cb(label)) {
        lv_label_ext_t * ext = (lv_label_ext_t *)lv_obj_get_ext_attr(label);
        ext->old_sign_cb = lv_obj_get_signal_cb(label);        //save label signal cb
        lv_obj_set_signal_cb(label, lv_lang_label_sign_cb);     //set new signal cb
    }

    /*Apply the new language*/
    lv_signal_send(label, LV_SIGNAL_LANG_CHG, NULL);
}

#endif /*LV_USE_MULTI_LANG*/
